// 睡眠锁实现
// 用于文件系统，允许在持有锁时睡眠

#include "types.h"
#include "defs.h"
#include "proc.h"
#include "spinlock.h"
#include "fs/sleeplock.h"

void
initsleeplock(struct sleeplock *lk, char *name)
{
  lk->name = name;
  lk->locked = 0;
  lk->pid = 0;
  initlock(&lk->lk, "sleep lock");
}

void
acquiresleep(struct sleeplock *lk)
{
  acquire(&lk->lk);
  
  struct proc *p = myproc();
  if(p == 0) {
    // 初始化阶段：如果没有进程
    // 如果锁已被持有（pid == 0 表示初始化阶段持有），直接返回
    // 因为初始化阶段是单线程的，同一个缓冲区可以被多次引用
    if(lk->locked && lk->pid == 0) {
      // 锁已被初始化阶段的调用持有，直接返回
      release(&lk->lk);
      return;
    }
    // 如果锁未被持有，获取它
    if(lk->locked) {
      // 这种情况不应该发生（锁被持有但 pid 不是 0）
      release(&lk->lk);
      panic("acquiresleep: lock held with non-zero pid during initialization");
    }
    lk->locked = 1;
    lk->pid = 0;
    release(&lk->lk);
    return;
  }
  
  // 正常情况：有进程，可以睡眠等待
  while (lk->locked) {
    sleep(lk, &lk->lk);
  }
  lk->locked = 1;
  lk->pid = p->pid;
  release(&lk->lk);
}

void
releasesleep(struct sleeplock *lk)
{
  acquire(&lk->lk);
  lk->locked = 0;
  lk->pid = 0;
  wakeup(lk);
  release(&lk->lk);
}

int
holdingsleep(struct sleeplock *lk)
{
  int r;
  acquire(&lk->lk);
  struct proc *p = myproc();
  if(p) {
    r = lk->locked && (lk->pid == p->pid);
  } else {
    r = lk->locked && (lk->pid == 0);  // 初始化阶段
  }
  release(&lk->lk);
  return r;
}